import React, {createContext, forwardRef, ReactNode, useImperativeHandle} from "react";
import useStore, {FormState} from "./useStore";
import {ValidateError} from "async-validator";
export type RenderProps = (form: FormState) => ReactNode

interface FormProps {
    name?: string
    initialValues?: Record<string, any>
    children?: ReactNode | RenderProps;
    onFinish?:(values:Record<string, any>)=>void
    onFinishFailed?:(values:Record<string, any>,errors:Record<string, ValidateError[]>)=>void
}

export type IFormContext = Pick<ReturnType<typeof useStore>, 'dispatch' | 'fields'|'validateField'> & Pick<FormProps, 'initialValues'>
export type IFormRef = Omit<ReturnType<typeof useStore>, 'fields' | 'dispatch' | 'form'>

export const FormContext = createContext<IFormContext>({} as IFormContext)
export const Form = forwardRef<IFormRef, FormProps>((props, ref) => {
    const { name, children, initialValues, onFinish, onFinishFailed } = props
    const { form, fields, dispatch, ...restProps } = useStore(initialValues)
    const { validateField, validateAllFields } = restProps
    useImperativeHandle(ref, () => {
        return {
            ...restProps
        }
    })
    const passedContext: IFormContext = {
        dispatch,
        fields,
        initialValues,
        validateField
    }
    const submitForm = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault()
        e.stopPropagation()
        const { isValid, errors, values } = await validateAllFields()
        if (isValid && onFinish) {
            onFinish(values)
        } else if(!isValid && onFinishFailed) {
            onFinishFailed(values, errors)
        }
    }
    let childrenNode: ReactNode
    if (typeof children === 'function') {
        childrenNode = children(form)
    } else {
        childrenNode = children
    }
    return (
        <form name={name} className="viking-form" onSubmit={submitForm}>
            <FormContext.Provider value={passedContext}>
                {childrenNode}
            </FormContext.Provider>
        </form>
    )
})


export default Form

Form.defaultProps = {
    name: 'viking-form'
}